package com.xy6.jvm.thread.account;

/**
 * 多线程示例
 * <pre>
 * 每次执行的结果都是不确定的，因为线程的执行顺序是不可预见的。
 * 这是java同步产生的根源，
 * synchronized关键字保证了多个线程对于同步块是互斥的，synchronized作为一种同步手段，
 * 解决java多线程的执行有序性和内存可见性，而volatile关键字之解决多线程的内存可见性问题。
 * </pre>
 * 
 * @author zhang
 * @since 2018-05-01
 */
public class Account {

	private int balance;

	public Account(int balance) {

		this.balance = balance;

	}

	public int getBalance() {

		return balance;

	}

	/**
	 * 添加 同步标记后，执行结果始终为 2001000 
	 * 此时，锁的是这个方法所在的对象，即Account的实例变量。
	 * 如果方法是public  static synchronized void add(int num)，那么锁就是这个方法所在的class。
	 * 
	 * @param num
	 */
	public synchronized void add(int num) {

		balance = balance + num;

	}

	public synchronized void withdraw(int num) {

		balance = balance - num;

	}

	public static void main(String[] args) throws InterruptedException {

		Account account = new Account(1000);

		Thread a = new Thread(new AddThread(account, 20), "add");

		Thread b = new Thread(new WithdrawThread(account, 20), "withdraw");

		a.start();

		b.start();

		a.join();

		b.join();

		System.out.println(account.getBalance());
	}

	static class AddThread implements Runnable {

		Account account;

		int amount;

		public AddThread(Account account, int amount) {

			this.account = account;

			this.amount = amount;

		}

		public void run() {

			for (int i = 0; i < 200000; i++) {

				account.add(amount);

			}

		}

	}

	static class WithdrawThread implements Runnable {

		Account account;

		int amount;

		public WithdrawThread(Account account, int amount) {

			this.account = account;

			this.amount = amount;

		}

		public void run() {

			for (int i = 0; i < 100000; i++) {

				account.withdraw(amount);

			}

		}

	}

}